/*
********************************************************************************
*
*	file : mian.c
*
********************************************************************************
*/
#include "tx_user.h"
#include "pincfg.h"
#include "bsp_hal.h"
#include "sys_com.h"
#include "os_obj.h"
#include "dataproc.h"

/*
********************************************************************************
*                              function
********************************************************************************
*/

void  app_printf(const char *fmt, ...);
void disp_task_info(void);
void  OSStatInit(void);

/*
********************************************************************************
*                               var
********************************************************************************
*/



__IO uint8_t   b_stat_rdy;        /* 统计任务就绪标志 */
__IO uint32_t  idle_loop_cnt;        /* 空闲任务计数 */
__IO float     f_cpu_usage;       /* CPU百分比 */
uint32_t       idle_loop_max;     /* 1秒内最大的空闲计数 */
uint32_t       idle_loop_min;     /* 1秒内空闲任务当前计数 */

/*******************************************************************************
* @brief  main : std proc entry.
* \param[in] none
* \retval: none
*******************************************************************************/
int main(void)
{
    //cpu init
    System_Init();

    //app time tick suspend
    app_tick_suspend();

    //os entry
    tx_kernel_enter();

    while (1);
}


/*******************************************************************************
* @brief  tx_application_define : called by tx_kernel_enter.
* \param[in] first_unused_memory :mem address that is unused
* \retval: none
*******************************************************************************/
void  tx_application_define(void *first_unused_memory)
{
    os_thread_init();
}


/*******************************************************************************
* @brief  app_task_start : task entry.
* \param[in] thread_input : argv
* \retval: none
*******************************************************************************/
void  app_task_start(ULONG thread_input)
{
    (void)thread_input;

    bsp_Init();

    os_thread_creat();

    //app tick run
    app_tick_resume();

    tx_thread_suspend(&os_obj.tcb_task_user);

    OSStatInit();

    tx_thread_resume(&os_obj.tcb_task_user);



    while (1)
    {
        tx_thread_sleep(1000);
    }
}


/*******************************************************************************
* @brief  app_task_user : task entry.
* \param[in] thread_input : argv
* \retval: none
*******************************************************************************/
void app_task_user(ULONG thread_input)
{
    uint32_t ucKeyCode, ucKeyCodeOld;
    uint32_t key_cnt;
    ULONG msg;
    UINT os_err;

    (void)thread_input;

    while (1)
    {
        ucKeyCode = I_KEY.in_st();
        key_cnt++;

        if (ucKeyCode != 0 && ucKeyCodeOld != ucKeyCode)
        {
            //disp_task_info();
            msg = key_cnt;
            os_err = tx_queue_send(os_obj.qid_tst,
                &msg,
                TX_NO_WAIT);
            os_api_exe_check();


            os_err = tx_event_flags_set(os_obj.eid_tst,
                0x02,
                TX_OR);
            os_api_exe_check();

            disp_task_info();
        }

        ucKeyCodeOld = ucKeyCode;

        tx_thread_sleep(16);
    }
}



/*******************************************************************************
* @brief  OSStatInit
* \param[in] none
* \retval: none
*******************************************************************************/
void  OSStatInit(void)
{
    b_stat_rdy = 0;

    tx_thread_sleep(2u);        /* 时钟同步 */

    b_stat_rdy = 1;
}

/*******************************************************************************
* @brief  app_task_stat : task entry.
* \param[in] thread_input : argv
* \retval: none
*******************************************************************************/
void app_task_stat(ULONG thread_input)
{
    uint32_t cal;

    (void)thread_input;

    while (b_stat_rdy == 0)
    {
        tx_thread_sleep(200);     /* 等待统计任务就绪 */
    }

    for (;;)
    {

        cal = idle_loop_cnt;    /* 获得100ms内空闲计数 */
        idle_loop_cnt = 0uL;          /* 复位空闲计数 */

        cal *= 1000;
        f_cpu_usage = 100.0f - ((float)cal / SystemCoreClock)*100;
        
        tx_thread_sleep(ms_ticks(1000));        /* 每100ms统计一次 */
    }
}

/*******************************************************************************
* @brief  app_task_idle : task entry.
* \param[in] thread_input : argv
* \retval: none
*******************************************************************************/
void app_task_idle(ULONG thread_input)
{
    TX_INTERRUPT_SAVE_AREA;

    (void)thread_input;
    NOP1();
    EvenU8(0x55);

idle_loop_start:
    //计算指令数保证该段执行1us//本例程此算192指令周期
    TX_DISABLE; //2
    idle_loop_cnt++;//3
    TX_RESTORE; //1
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP20();
    NOP40(); NOP40(); NOP11();
    goto idle_loop_start;//1
}

/*******************************************************************************
* @brief  app_printf
* \param[in] fmt : argv
* \retval: none
*******************************************************************************/
void  app_printf(const char *fmt, ...)
{
    char  buf_str[200 + 1]; //print buffer
    va_list   v_args;

    va_start(v_args, fmt);

    (void)vsnprintf((char       *)&buf_str[0],
        (size_t) sizeof(buf_str),
        (char const *)fmt,
        v_args);

    va_end(v_args);

    //mutex opt
    tx_mutex_get(&os_obj.mutex_printf, TX_WAIT_FOREVER);

    sys_puts(buf_str);

    tx_mutex_put(&os_obj.mutex_printf);
}

/*******************************************************************************
* @brief  disp_task_info
* \param[in] none
* \retval: none
*******************************************************************************/
void disp_task_info(void)
{
    TX_THREAD      *p_tcb;

    p_tcb = &os_obj.tcb_app_task_start;

    //print head
    app_printf("===============================================================\n");
    app_printf("OS CPU Usage = %5.2f%%\n", f_cpu_usage);
    app_printf("===============================================================\n");

    app_printf("   Prio StackSize CurStack MaxStack Taskname\n");

    //task infomation print
    while (p_tcb != (TX_THREAD *)0)
    {

        app_printf("   %2d    %5d    %5d    %5d    %s\n",
            p_tcb->tx_thread_priority,
            p_tcb->tx_thread_stack_size,
            (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_ptr,
            (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_highest_ptr,
            p_tcb->tx_thread_name);


        p_tcb = p_tcb->tx_thread_created_next;

        if (p_tcb == &os_obj.tcb_app_task_start) break;
    }
}


void lib_check_hook(uint8_t st)
{

}

void lib_os_lock(void){};
void lib_os_unlock(void){};
